/******************************************************************************/
package jamie.org.sil.www.usxUtils;


/******************************************************************************/
/**
 * An interface which defines methods to be called to convert a parsed text
 * string into string form.  The default version of toString(ParsedTextElementBibleRef ref)
 * here simply converts the reference into string form.  You're likely to want
 * to override this to add functionality to generate links etc.
 * <p>
 * 
 * Don't be tempted to change the "final" designations below -- the methods
 * you want to override are the versions which take lots of parameters,
 * because these are the ones which all the processing funnels down to.
 *
 * @author Jamie
 */

public class ParsedTextOutputter
{
  /****************************************************************************/
  /****************************************************************************/
  /**                                                                        **/
  /**                               Public                                   **/
  /**                                                                        **/
  /****************************************************************************/
  /****************************************************************************/

  
  /****************************************************************************/
  public void setLanguage (BibleReferenceSupport.Language val) { m_EnglishOrVernacular = val; }
  public void setLength (BibleReferenceSupport.Length val) { m_FullOrAbbreviated = val; }
  public void setIncludeDefaultedValues (boolean val) { m_IncludeDefaultedValues = val; }
  public void setSepStyle (int val) { m_SepStyle = val; }


  /****************************************************************************/
  /**
   * Called to output anything which may be needed after an embedded reference.
   * All the various settings are derived from the instance variables.
   * 
   * @param ref Bible reference.
   * 
   * @return Any string which should be written out at this point.
   */
  
  final public String toString (ParsedText pt)
  {
    return toString(pt, m_FullOrAbbreviated, m_EnglishOrVernacular, m_SepStyle, m_IncludeDefaultedValues);
  }


  /****************************************************************************/
  /**
   * Called to output anything which may be needed after an embedded reference.
   * All the various settings are derived from the instance variables.
   * 
   * @param ref Bible reference.
   * 
   * @return Any string which should be written out at this point.
   */
  
  final public String toString (ParsedTextElementBibleRef ref)
  {
    return toString(ref, m_FullOrAbbreviated, m_EnglishOrVernacular, m_SepStyle, m_IncludeDefaultedValues);
  }


  /****************************************************************************/
  /**
   * Called to output anything which may be needed after an embedded reference.
   * 
   * @param ref Bible reference.
   * 
   * @param fullOrAbbreviated   Indicates whether book names should be provided
   *                            in full or abbreviated.
   * 
   * @param englishOrVernacular Indicates whether book names and numerals should
   *                            be in English or vernacular.
   *
   * @param sepStyle BibleReferenceSupport.C_SeparatorInternal or C_SeparatorExternal
   * 
   * @param includeDefaultedValues  If true, defaulted book names, chapters, etc
   *                                are output.
   * 
   * @return Any string which should be written out at this point.
   */
  
  public String toString (ParsedTextElementBibleRef ref,
                          BibleReferenceSupport.Length fullOrAbbreviated,
                          BibleReferenceSupport.Language englishOrVernacular,
                          int sepStyle,
                          boolean includeDefaultedValues)
  {
    return ref.toString(fullOrAbbreviated, englishOrVernacular, sepStyle, includeDefaultedValues);
  }



  /****************************************************************************/
  /**
   * Converts the current element to string form, constructing a suitable
   * converter for the purpose.
   * 
   * @param pt Parsed text instance.
   * 
   * @param fullOrAbbreviated   Indicates whether book names should be provided
   *                            in full or abbreviated.
   * 
   * @param englishOrVernacular Indicates whether book names and numerals should
   *                            be in English or vernacular.
   *
   * @param sepStyle BibleReferenceSupport.C_SeparatorInternal or C_SeparatorExternal
   * 
   * @param includeDefaultedValues  If true, defaulted book names, chapters, etc
   *                                are output.
   * 
   * @param refOutputter Handles references in the output.
   *
   * @return String.
   */
  
  final public String toString (ParsedText pt,
                                BibleReferenceSupport.Length fullOrAbbreviated,
                                BibleReferenceSupport.Language englishOrVernacular,
                                int sepStyle,
                                boolean includeDefaultedValues)
  {
    /**************************************************************************/
    int ix = 0;
    int lim = pt.m_Tokens.size();
    String res = "";
 
    
    
    /**************************************************************************/
    /* Where we have Bible reference ranges and are generating links (such
     * as hrefs), I generally try to generate a link which points at the
     * _start_ of the range, and where piece of text you can click on to
     * follow the link covers the whole text of the reference.
     * 
     * However, if either the start or the end reference does not exist,
     * I don't want to generate the link at all.  The code which generates
     * the output therefore needs to know if we have any things which
     * look like range-references, but which point nowhere.
    */
    
    while (ix < lim - 2)
    {
      ParsedTextElement pte1 = pt.m_Tokens.get(ix);
      ParsedTextElement pte2 = pt.m_Tokens.get(ix + 1);
      ParsedTextElement pte3 = pt.m_Tokens.get(ix + 2);
      if ((pte1 instanceof ParsedTextElementBibleRef) &&
          (pte2 instanceof ParsedTextElementSeparator) &&
          (pte3 instanceof ParsedTextElementBibleRef))
      {
        ix += 2;
        ParsedTextElementSeparator ptes = (ParsedTextElementSeparator) pte2;
        int separatorCode = BibleReferenceSupport.instance().getBaseCode(ptes.getSeparatorCode());
        if (BibleReferenceSupport.C_Separator_RangeDifferentChapters == separatorCode ||
            BibleReferenceSupport.C_Separator_RangeSameChapter == separatorCode)
        {
          ParsedTextElementBibleRef ptebr1 = (ParsedTextElementBibleRef) pte1;
          ParsedTextElementBibleRef ptebr2 = (ParsedTextElementBibleRef) pte3;
          boolean targetExists =
            BookAssembly.instance().referenceTargetExists(BibleDetails.instance().getAbbreviatedUbsName_E(ptebr1.getFullEnglishBookName()), Integer.parseInt(ptebr1.getChapter()));
          targetExists = targetExists && BookAssembly.instance().referenceTargetExists(BibleDetails.instance().getAbbreviatedUbsName_E(ptebr2.getFullEnglishBookName()), Integer.parseInt(ptebr2.getChapter()));
          if (!targetExists)
          {
            ptebr1.setFormsPartOfRangeForWhichTargetDoesNotExist(true);
            ptebr2.setFormsPartOfRangeForWhichTargetDoesNotExist(true);
          }
          
        }
      }
      
      ++ix;
    }

    
    
    /**************************************************************************/
    /* Now do the actual text generation. */
    
    for (ix = 0; ix < lim; ++ix)
    {
      ParsedTextElement pte = pt.m_Tokens.get(ix);
      if (pte instanceof ParsedTextElementBibleRef)
        res += toString((ParsedTextElementBibleRef) pte, fullOrAbbreviated, englishOrVernacular, sepStyle, includeDefaultedValues);
      else
        res += pte.toString(fullOrAbbreviated, englishOrVernacular, sepStyle, includeDefaultedValues);
    }

    return res;
  }




  /****************************************************************************/
  /****************************************************************************/
  /**                                                                        **/
  /**                               Public                                   **/
  /**                                                                        **/
  /****************************************************************************/
  /****************************************************************************/

  /****************************************************************************/
  private BibleReferenceSupport.Language m_EnglishOrVernacular = BibleReferenceSupport.Language.C_Vernacular;  
  private BibleReferenceSupport.Length m_FullOrAbbreviated   = BibleReferenceSupport.Length.C_AsSupplied;  
  private boolean m_IncludeDefaultedValues = false;
  private int m_SepStyle = BibleReferenceSupport.C_SeparatorExternal;
}
